﻿namespace Practices.IdentityProvider {
    using Microsoft.AspNet.Identity;
    using Microsoft.AspNet.Identity.EntityFramework;
    using Microsoft.AspNet.Identity.Owin;
    using Microsoft.Owin;
    using Microsoft.Owin.Security;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using System.Web;

    public class ApplicationUser : IdentityUser {
        public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager) {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = manager.CreateIdentity(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            userIdentity.AddClaim(new Claim(ClaimTypes.Upn, this.UserName));
            return userIdentity;
        }

        public Task<ClaimsIdentity> GenerateUserIdentityAsync(ApplicationUserManager manager) {
            return Task.FromResult(GenerateUserIdentity(manager));
        }
    }

    public class ApplicationUserStore : IUserStore<ApplicationUser>,
        IUserLockoutStore<ApplicationUser, string>,
        IUserTwoFactorStore<ApplicationUser, string> {
        #region IUserStore

        public Task CreateAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        public Task UpdateAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        public Task DeleteAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Finds a user
        /// </summary>
        public Task<ApplicationUser> FindByIdAsync(string userId) {
            return Task.FromResult(new ApplicationUser() {
                Id = userId,
                UserName = userId
            });
        }

        /// <summary>
        /// Find a user by name
        /// </summary>
        public Task<ApplicationUser> FindByNameAsync(string userName) {
            return Task.FromResult(new ApplicationUser() {
                Id = userName,
                UserName = userName
            });
        }

        #endregion

        #region IUserLockoutStore

        /// <summary>
        /// Returns the current number of failed access attempts. This number usually
        //  will be reset whenever the password is verified or the account is locked out.
        /// </summary>
        public Task<int> GetAccessFailedCountAsync(ApplicationUser user) {
            return Task.FromResult(0);
        }

        /// <summary>
        /// Returns whether the user can be locked out.
        /// </summary>
        public Task<bool> GetLockoutEnabledAsync(ApplicationUser user) {
            return Task.FromResult(false);
        }

        public Task<DateTimeOffset> GetLockoutEndDateAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        public Task<int> IncrementAccessFailedCountAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        public Task ResetAccessFailedCountAsync(ApplicationUser user) {
            throw new NotImplementedException();
        }

        public Task SetLockoutEnabledAsync(ApplicationUser user, bool enabled) {
            throw new NotImplementedException();
        }

        public Task SetLockoutEndDateAsync(ApplicationUser user, DateTimeOffset lockoutEnd) {
            throw new NotImplementedException();
        }

        #endregion

        #region IUserTwoFactorStore

        /// <summary>
        /// Returns whether two factor authentication is enabled for the user
        /// </summary>
        public Task<bool> GetTwoFactorEnabledAsync(ApplicationUser user) {
            return Task.FromResult(false);
        }

        public Task SetTwoFactorEnabledAsync(ApplicationUser user, bool enabled) {
            throw new NotImplementedException();
        }

        #endregion

        public void Dispose() {
            
        }        
    }

    public class ApplicationUserManager : UserManager<ApplicationUser> {
        public ApplicationUserManager(IUserStore<ApplicationUser> store)
            : base(store) {
        }

        public override Task<bool> CheckPasswordAsync(ApplicationUser user, string password) {
            //if (IdentityHelper.ValidateCertificate(HttpContext.Current.Request.ClientCertificate)
            //    && IdentityHelper.ValidateHostAddress(HttpContext.Current.Request.UserHostAddress)) {
            //    return Task.FromResult(true);
            //} else {
            //    return Task.FromResult(false);
            //}
            return Task.FromResult(true);
        }

        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) {
            var manager = new ApplicationUserManager(new ApplicationUserStore());
            return manager;
        }
    }

    public class ApplicationSignInManager : SignInManager<ApplicationUser, string> {
        public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) :
            base(userManager, authenticationManager) {
        }

        public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user) {
            return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
        }

        public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context) {
            return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
        }
    }
}